package service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;

import bean.MailResume;
import dao.MailManagerDao;
import dao.UserManagerDao;
import dao.MailManagerDaoImpl;
import dao.UserManagerDaoImpl;
/*
 * last modified: 2018/05/01
 * author: hql
 */
public class POP3Server extends Thread {
	private static volatile boolean ok;
	private static ServerSocket s = null;
	private static Socket socket = null;
	public static boolean getOk() {
		return ok;
	}
	public void run( ) {
		if (ok) return;
		ok = true;
		Server2.open();
		try {
			s = new ServerSocket(110);
			while (ok) {
				socket = s.accept();
				if (!ok) break;
				new Server2(socket).start();
			}
			if(socket != null) socket.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void close() {
		ok = false;
		try {
			if(s != null) s.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Server2.close();
	}
	
	public static void main(String[] args) {
		new POP3Server().start();
		int i;
		@SuppressWarnings("resource")
		Scanner scan= new Scanner(System.in);
		while (true) {
			i=scan.nextInt();
			System.out.println(i);
			if (i==1) {
				POP3Server.close();
				break;
			}
		}
	}
}

class Server2 extends Thread{
	private Socket socket;
	@SuppressWarnings("unused")
	private static volatile boolean close_all;
	private static UserManagerDao userimpl = new UserManagerDaoImpl();
	private static MailManagerDao mailimpl = new MailManagerDaoImpl();
	//private Base64.Decoder decoder = Base64.getDecoder();//后期邮件解码需要用到
	//private Base64.Encoder encoder = Base64.getEncoder();
	public Server2(Socket s) {
		socket = s;
	}
	public static void open() {
		close_all = false;
	}
	public static void close() {
		close_all = true;
	}
	public static boolean isInteger(String str) {  //判断输入是否为整数
	    Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");  
	    return pattern.matcher(str).matches();  
	}
	public void run() {
		PrintWriter pw = null;
		BufferedReader br = null;
		boolean user = false;
		boolean pass = false;
		boolean login = false;
		String clientName = null;
		List<Integer> deleMailList = new ArrayList<Integer>();//保存所有可能删除的邮件id的list，List为接口，用ArrayList实现
		List<Integer> totalMailList = new ArrayList<Integer>();//维护当前可以显示的邮件id的list，可能删除的不显示
		//String contents = null;
		try {
			OutputStream os = socket.getOutputStream();
			pw = new PrintWriter(os, true);
			InputStreamReader is = new InputStreamReader(socket.getInputStream());
			br = new BufferedReader(is);
			pw.println("+OK Welcome to coremail Mail Pop3 Server(suki570)");
			while (true) {
				if (close_all) {
					pw.println("221 server is closed!");
					break;
				}
				String input = br.readLine().toLowerCase();
				System.out.println(input);
				String[] commands = input.split(" ");//将一个字符串分割为子字符串，然后将结果作为字符串数组返回传递的参数为分隔符。
				if (commands[0].equals("quit")) {//返回到确认状态(需重新身份验证),并将标记为删除的邮件都删除。
					if(deleMailList != null) {
						for (Integer dml: deleMailList) {
							mailimpl.deleteMail(clientName, dml);
							System.out.println("OK, finally I delete "+dml);
						}	
					}
					pw.println("+OK core mail");
					break;
				} else {
					switch(commands[0]) {
					case "user"://用户名，已完成
						if (!user) {
							System.out.println("loading..");
							if (commands.length == 1) {
								pw.println("-ERR Username not valid");
							}
							else {//if (commands[1].equals("daisy1z") && !user) {为了方便测试用例，实际中获得用户名后先不搜索数据库而是直接进行密码匹配。
								user = true;
								pw.println("+OK core mail");
								clientName = commands[1];	
								System.out.println("clientName .. "+clientName);
							}
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
					case "pass"://密码，已完成
						if (user && !login) {
							if (commands.length == 1) {
								pw.println("-ERR Password not valid");
							} else {
								if(userimpl.isUser(clientName) && userimpl.getUser(clientName).get(0).getPassword().equals(commands[1])) {
									pass = true;
									login = true;
									int mailNum = 0;
									List<MailResume> mrlist = mailimpl.getAllMail(clientName);
									for(MailResume mrl : mrlist) {//初始化所有当前clientName的对应邮件编号
										//if是收到标志位为1 {
										int textLength = mailimpl.getMail(mrl.getMail_id()).getContent().length();
										mailNum += textLength;
										totalMailList.add(mrl.getMail_id());
									}
									pw.println("+OK "+userimpl.getUserTotalMail(clientName)+" message(s) ["+mailNum+" byte(s)]");//返回该账号的邮件数量，大小。
									//pw.println("+OK "+userimpl.getUserTotalMail(clientName)+" message(s) ["+999+" byte(s)]");返回该账号的邮件数量，大小。	
								} else {
									user = false;
									clientName = null;
									pw.println("-ERR Unable to log on");
								}
							}
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
					//case "apop":
					case "stat"://返回该账号的邮件总数量，大小。已完成
						if (pass) {
							int mailNum = 0;
							for(Integer tml : totalMailList) {//初始化所有当前clientName的对应邮件编号
								//if是收到标志位为1 {
								int textLength = mailimpl.getMail(tml).getContent().length();
								mailNum += textLength;
							}
							pw.println("+OK "+totalMailList.size()+" message(s) ["+mailNum+" byte(s)]");	
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
				   
				   /**
					* UIDL 邮件编号\r\n      	方式一：获取指定邮件唯一标识符(每一个邮件都有一个唯一标识符)
					* UIDL\r\n                 方式二：获取所有邮件的唯一标识符(每一个编码,对应它的ID)
					*/
					case "uidl":
						if (pass) {
							if (commands.length == 1) {//从数据库中取出所有邮件标识“编号+标识符”
								int i = 1;
								for(Integer tml : totalMailList){
						            pw.println(i+" "+tml);
						            i++;
								}
								pw.println(".");
								//pw.println("list-i have gotten what i want!");//从数据库中取出所有邮件标识“编号+邮件大小（十进制）”
							} else {
								if (pass && commands.length == 2 && isInteger(commands[1]) &&
										Integer.parseInt(commands[1]) > 0 && 
										Integer.parseInt(commands[1]) <= totalMailList.size()) {
									int curMail = Integer.parseInt(commands[1]);
									int curMailId = totalMailList.get(curMail-1);
									pw.println("+OK "+curMail+" "+curMailId);
									//pw.println("+OK "+"邮件编号如：334"+"唯一标识符如：dsnfnsdjfmnsjkfcmsl");
								} else {
									pw.println("+ERR Unknown message");
								}
							}							
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
						
					/**
					 * LIST 邮件编号\r\n      方式一：获取指定邮件的字节大小(注意:不包括".\r\n"的长度)
					 * LIST\r\n	           方式二：获取所有邮件的字节大小(每一个编码,对应它的大小)
					 * 已完成
					 */	
					case "list":
						if (pass) {
							if (commands.length == 1) {
								int i = 1;
								for(Integer tml : totalMailList){
						            int textLength = mailimpl.getMail(tml).getContent().length();
						            pw.println(i+" "+textLength);
						            i++;
								}
								pw.println(".");
								//pw.println("list-i have gotten what i want!");//从数据库中取出所有邮件标识“编号+邮件大小（十进制）”
							} else {
								if (pass && commands.length == 2 && isInteger(commands[1]) &&
										Integer.parseInt(commands[1]) > 0 && 
										Integer.parseInt(commands[1]) <= totalMailList.size()) {
									int curMail = Integer.parseInt(commands[1]);
									int curMailId = totalMailList.get(curMail-1);
									pw.println("+OK "+curMail+" "+mailimpl.getMail(curMailId).getContent().length());
									//pw.println("+OK "+"邮件编号如：334"+"邮件大小如：1497");
								} else {
									pw.println("+ERR Unknown message");
								}
							}							
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
						
					/**
					 * RETR 邮件编号\r\n	下载指定邮件,服务器会发送两个封包,先发送长度(注意:不包括".\r\n"的长度)再发送整个邮件
					 * 已完成
					 */
					case "retr"://已完成
						if (pass) {
							if(commands.length == 2 && isInteger(commands[1]) && 
									Integer.parseInt(commands[1]) > 0 && 
									Integer.parseInt(commands[1]) <= totalMailList.size()) {
								int curMail = Integer.parseInt(commands[1]);
								int curMailId = totalMailList.get(curMail-1);//用户第x封邮件对应的mail_id
								pw.println("+OK "+commands[1]+" octets\r\n"+mailimpl.getMail(curMailId).getContent());
								pw.println(".");
							} else {
								pw.println("-ERR Unknown command");
							}
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
					case "dele"://已完成，删除所有群发邮件对应关系前会抛出异常，最后一封不会有异常
						if (pass) {
							if(commands.length == 2 && isInteger(commands[1]) && //isInteger判断commands[1]是否为整数
									Integer.parseInt(commands[1]) > 0 && 
									Integer.parseInt(commands[1]) <= totalMailList.size()) {
								int curMail = Integer.parseInt(commands[1]);
								int curMailId = totalMailList.get(curMail-1);
								//int curMailId = mailimpl.getAllMail(clientName).get(curMail-1).getMail_id();用户第x封邮件对应的mail_id
								//mailimpl.deleteMail(clientName, curMailId);
								deleMailList.add(curMailId);
								totalMailList.remove(curMail-1);//移除第curMail封邮件
								pw.println("+OK core mail");
							} else {
								pw.println("-ERR Unknown command");
							}
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
					case "rset"://已完成
						if (pass) {
							totalMailList.clear();
							List<MailResume> mrlist = mailimpl.getAllMail(clientName);
							for(MailResume mrl : mrlist) {//初始化所有当前clientName的对应邮件编号
								//if是收到标志位为1 {
								totalMailList.add(mrl.getMail_id());
							}
							deleMailList.clear();
							pw.println("+OK core mail");
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
					
					/**
					 * TOP 邮件编号 前n行\r\n	下载邮件的前n行内容,服务器会发送两个封包,先发送长度(注意:是总长度,而且不包括".\r\n"的长度)再发送包括信头的前n行邮件内容
					 * 未实现
					 */
					case "top":
						if (pass && commands.length == 3/* && commands[1][2]属于正常范围*/) {
							pw.println("+OK top");
						} else {
							pw.println("-ERR Command not valid in this state");
						}
						break;
					//noop
					default:
						pw.println("-ERR Unknown command "+input);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} try {
			if (br != null) br.close();
			if (pw != null) pw.close();
			if (socket != null) socket.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}
